package com.huajx.mina.tcpserver.acceptor;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import com.huajx.util.ObjectUtil;
import org.apache.mina.core.service.IoAcceptor;
import org.apache.mina.core.service.IoHandler;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.executor.ExecutorFilter;
import org.apache.mina.filter.keepalive.KeepAliveFilter;
import org.apache.mina.filter.keepalive.KeepAliveMessageFactory;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.huajx.ld.codec.TbProtocolCodecFactory;
import com.huajx.tcpserver.kit.MessageKit;


/**
 * mina服务端
 * 
 * @author xhye
 *
 */
public class SerNioSocketAcceptor {
	IoAcceptor acceptor;
	IoHandler ioHandler;
	int[] ports;

	boolean serverRunning = false;// 服务是否正在运行

	// 记录日志
	private static Logger logger = LoggerFactory.getLogger(SerNioSocketAcceptor.class);

	/**
	 * 创建bind()方法接收连接
	 * 
	 * @throws IOException
	 */
	public void bind() throws IOException {
		if (serverRunning) {
			return;
		}

		if (ObjectUtil.isEmpty(ports)) {
			logger.info("服务端启动失败，未设置端口"); // 测试使用
		}

		// 创建 协议编码解码过滤器ProtocolCodecFilter
		// 设置序列化Object 可以自行设置自定义解码器
		ProtocolCodecFilter pf = new ProtocolCodecFilter(new TbProtocolCodecFactory("GBK", false, false));
		// getFilterChain() 获取 I/O 过滤器链，可以对 I/O 过滤器进行管理，包括添加和删除 I/O 过滤器。
		acceptor = new NioSocketAcceptor();
		// // 设置缓存大小
		 acceptor.getSessionConfig().setReadBufferSize(1024);

		// 设置过滤器
		acceptor.getFilterChain().addLast("executor", new ExecutorFilter());
		acceptor.getFilterChain().addLast("logger", new LoggingFilter());
		acceptor.getFilterChain().addLast("codec", pf);

		KeepAliveMessageFactory kamf = new KeepAliveMessageFactoryImpl();
		KeepAliveFilter kaf = new KeepAliveFilter(kamf, IdleStatus.BOTH_IDLE);
		kaf.setForwardEvent(true);
		kaf.setRequestInterval(60); // 本服务器为被定型心跳 即需要每30秒接受一个心跳请求 否则该连接进入空闲状态
									// 并且发出idled方法回调
		acceptor.getFilterChain().addLast("heart", kaf);

		// 读写通道60秒内无操作进入空闲状态
		acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 60000);
		// 绑定逻辑处理器
		acceptor.setHandler(ioHandler);

		List<SocketAddress> socketAddresses = new ArrayList<>();

		StringBuilder sb = new StringBuilder();
		for (int port : ports) {
			socketAddresses.add(new InetSocketAddress(port));
			sb.append(port).append(", ");
		}

		// 绑定端口
		acceptor.bind(socketAddresses);

		logger.info("服务端启动成功...端口号为:" + sb.toString()); // 测试使用

		serverRunning = true;
	}

	/**
	 * 创建unbind()方法停止监听
	 */
	public void unbind() {
		if (!serverRunning || acceptor == null) {
			serverRunning = false;
			return;
		}
		acceptor.unbind();
		acceptor.dispose();

		logger.info("服务端停止成功");

		serverRunning = false;
	}

	public void setAcceptor(IoAcceptor acceptor) {
		this.acceptor = acceptor;
	}

	/**
	 * 设置 I/O 处理器。 该 I/O 处理器会负责处理该 I/O 服务所管理的所有 I/O 会话产生的 I/O 事件。
	 * 
	 * @param ioHandler
	 */
	public void setIoHandler(IoHandler ioHandler) {
		this.ioHandler = ioHandler;
	}

	/**
	 * 设置端口
	 * 
	 * @param ports
	 */
	public void setPorts(int... ports) {
		this.ports = ports;
	}

	/**
	 * 获取该 I/O 服务所管理的 I/O 会话。
	 * 
	 * @return
	 */
	public Map<Long, IoSession> getManagedSessions() {
		return acceptor.getManagedSessions();
	}

	public boolean isServerRunning() {
		return serverRunning;
	}

	private class KeepAliveMessageFactoryImpl implements KeepAliveMessageFactory {
		private String response = null;
		
		@Override
		public boolean isRequest(IoSession session, Object message) {
			if(! (message instanceof byte[])){
				return false;
			}
			
			byte[] bytes = (byte[])message;
			
			if(bytes.length < 33){
				return false;
			}
			
			String tbz = MessageKit.getStr(bytes, 0, 3);
			String command = MessageKit.getStr(bytes, 30, 2);
			
			if (tbz.equals("TPJ") && "10".equals(command)) {
				String temp = MessageKit.getStr(bytes, 3, bytes.length - 3);
				response = "JTP" + temp;
				logger.info("心跳检测，请求参数{}", MessageKit.getStr(bytes, 0, bytes.length));
				return true;
			}

			return false;
		}

		@Override
		public boolean isResponse(IoSession session, Object message) {
			if((message instanceof String)){
				String msg = (String)message;
//				logger.info("包: {}", msg);
				
				byte[] bytes = msg.getBytes();
				
				if(bytes.length < 33){
					return false;
				}
				
				String tbz = MessageKit.getStr(bytes, 0, 3);
				
				String command = MessageKit.getStr(bytes, 30, 2);
				
				if (tbz.equals("JTP") && "10".equals(command)) {
					logger.info("心跳检测，响应参数{}", MessageKit.getStr(bytes, 0, bytes.length));
					return true;
				}
			}
			return false;
		}

		@Override
		public Object getRequest(IoSession session) {
			return null;
		}

		@Override
		public Object getResponse(IoSession session, Object request) {
			return response;
		}
	}
}
